package aa.app.dm;

import java.io.Serializable;

import aa.core.Actor;
import aa.core.Contract;
import aa.core.CyberOrg;
import aa.core.Platform;
import aa.tool.CyberOrgPublicTupleSpace;
import aa.tool.CyberOrgTuple;
import aa.tool.TupleSpaceException;
import aa.util.ObjectHandler;

/**
 *  This class provides three different types of middle man service:
 *  matchmaking, brokering, and active brokering service.
 * 
 *  <p>
 *  <b>History:</b>
 *  <ul>
 *      <li> February 19, 2004 - version 0.0.4
 *	<ul>
 *	    <li> move the active brokering service from this actor
 *		 to aa.app.atspace.ATSpace.
 *	    <li> add the 'update' method.
 *	</ul>
 *      <li> January 26, 2003 - version 0.0.3
 *      <ul>
 *          <li> modify this file.
 *      </ul>
 *      <li> May 9, 2003 - version 0.0.2
 *      <ul>
 *          <li> modify internal comments.
 *      </ul>
 *      <li> April 5, 2001 - version 0.0.1
 *      <ul>
 *          <li> create this file.
 *      </ul>
 *  </ul>
 *
 *  @author Mehadi Hasan
 *  @version $Date: 2011/04/12 00:23:55 $ $Revision: 1.1 $
 */
public class CyberOrgDirectoryManager extends Actor {
    // ========== Object Variables ========== //

    /**
     *  Tuple Space as a blackboard.
     */
    protected CyberOrgPublicTupleSpace m_pubTSpace;

    // ========== Object Methods ========== //
    /**
     *  Creates a Directory Manager.
     */
    public CyberOrgDirectoryManager() {
        m_pubTSpace = new CyberOrgPublicTupleSpace();
    }

    /**
     *  Delivers a message to a randomly selected actor
     *      whose information is matched with the given tuple pattern.
     * 
     *  @param p_ctReceiver the tuple pattern to find a receiver actor.
     *  @param p_strMethod the method name to be called.
     *  @param p_objaArgs arguments to be deliverd to the receiver actor.
     */
    protected boolean deliverImpl(CyberOrgTuple p_ctReceiver, String p_strMethod, Object[] p_objaArgs)
            throws Exception {
        CyberOrg anReceiver = search(p_ctReceiver);

        if (anReceiver != null) {
            sendMessage(anReceiver.getFacilitator(), p_strMethod, p_objaArgs);

            return true;
        } else {
            if (Platform.bERROR) {
                System.err.println("% TupleSpace.deliverMessage: "
                        + "WARNING - No actor is matched");
            }

            return false;
        }
    }

    /**
     *  Broadcasts a message to all actors 
     *      whose information is matched with the given tuple pattern.
     * 
     *  @param p_ctReceiver the tuple pattern to find receiver actors.
     *  @param p_strMethod the method name to be called.
     *  @param p_objaArgs arguments to be deliverd to receiver actors. 
     */
//    protected boolean deliverAllImpl(CyberOrgTuple p_ctReceiver, String p_strMethod, Object[] p_objaArgs)
//            throws Exception {
//        CyberOrg[] anaReceivers = searchAll(p_ctReceiver);
//
//        if ((anaReceivers != null) && (anaReceivers.length != 0)) {
//            for (int i = 0; i < anaReceivers.length; i++) {
//                sendMessage(anaReceivers[i].getFacilitator(), p_strMethod, p_objaArgs);
//            }
//
//            return true;
//        } else {
//            if (Platform.bERROR) {
//                System.err.println("> DirectoryManager.deliverAllImpl[1]: "
//                        + "WARNING - No actors are matched");
//            }
//
//            return false;
//        }
//    }
//
//    /**
//     *  Delivers a message to a randomly selected actor
//     *      whose information is matched with the given tuple pattern.
//     *
//     *  @param p_ctReceiver the tuple pattern to find a receiver actor.
//     *  @param p_strMethod the method name to be called.
//     *  @param p_objaArgs arguments to be deliverd to the receiver actor.
//     */
//    protected boolean deliver(CyberOrgTuple p_ctReceiver, String p_strMethod, Object[] p_objaArgs) {
//        try {
//            return (deliverImpl(p_ctReceiver, p_strMethod, p_objaArgs));
//        } catch (Exception e) {
//            if (Platform.bERROR) {
//                System.err.println("> DirectoryManager.deliver[1]: " + e);
//            }
//
//            return false;
//        }
//    }

    /**
     *  Broadcasts a message to all actors 
     *      whose information is matched with the given tuple pattern.
     * 
     *  @param p_ctReceiver the tuple pattern to find receiver actors.
     *  @param p_strMethod the method name to be called.
     *  @param p_objaArgs arguments to be deliverd to receiver actors. 
     */
//    protected boolean deliverAll(CyberOrgTuple p_ctReceiver, String p_strMethod, Object[] p_objaArgs) {
//        try {
//            return (deliverAllImpl(p_ctReceiver, p_strMethod, p_objaArgs));
//        } catch (Exception e) {
//            if (Platform.bERROR) {
//                System.err.println("% DirectoryManager.deliverAll[1]: " + e);
//            }
//
//            return false;
//        }
//    }

    /**
     *  Registers an CyberOrg tuple to this Directory Manager.
     *  
     *  @param p_ctTuple an CyberOrg tuple to be inserted in this Directory Manager.
     */
    public void register(CyberOrgTuple p_ctTuple) {
        try {
            m_pubTSpace.write(p_ctTuple);
            System.out.println("CDM entry: " + p_ctTuple.getDestination() + " " + p_ctTuple.getId() + " " + p_ctTuple.getFacClassName() + " " + p_ctTuple.getContract());
        } catch (TupleSpaceException e) {
            if (Platform.bERROR) {
                System.err.println("% CyberOrgDirectoryManager.register: " + e);
                e.printStackTrace();
            }
        }
    }

    /**
     *  Removes an CyberOrg tuple in this Directory Manager.
     * 
     *  @param p_ctTuple a tuple data to be removed in this Directory Manager.
     */
    public void deregister(CyberOrgTuple p_ctTuple) {
        try {
            System.err.println("removing entry from CDM..."+p_ctTuple.toString());
            m_pubTSpace.removeAll(p_ctTuple);
        } catch (TupleSpaceException e) {
            if (Platform.bERROR) {
                System.err.println("% DirectoryManager.remove: " + e);
                e.printStackTrace();
            }
        }
    }

    /**
     *  Removes CyberOrg tuples matched with the given tuple template,
     *      and then inserts an CyberOrg tuple in this tuple space.
     * 
     *  @param p_ctTemplate a tuple template to be used for matching with
     *                      CyberOrg tuples in this tuple space.
     *  @param p_ctTuple an CyberOrg tuple to be stored in this tuple space.
     */
    public void update(CyberOrgTuple p_ctTemplate, CyberOrgTuple p_ctTuple) {
        try {
            m_pubTSpace.update(p_ctTemplate, p_ctTuple);
        } catch (TupleSpaceException e) {
            if (Platform.bERROR) {
                System.err.println("% ATSpace.remove: " + e);
                e.printStackTrace();
            }
        }
    }

    /**
     *  Retrieves any one of names of CyberOrgs that
     *      support the specified tuple.
     *  
     *  @param p_atTemplate a tuple template to find the name of the CyberOrg
     *                      that supports the specified attributes.
     */
    public CyberOrg search(CyberOrgTuple p_ctTemplate)
            throws Exception {
        if (p_ctTemplate.getCyberOrg() != null) {
            throw new Exception("Exception: the field of CyberOrg should be null");
        }

        try {
            return m_pubTSpace.search(p_ctTemplate);
        } catch (TupleSpaceException e) {
            return null;
        }
    }

    public CyberOrgTuple[] returnAllTuples() {
        return m_pubTSpace.getCyberOrgTuples();
    }

    /**
     *  Retrieves names of all CyberOrgs that
     *      support the specified attribute.
     *  
     *  @param p_atTemplate a tuple template to find the CyberOrg 
     *                      that supports the specified attributes.
     */
    public CyberOrgTuple[] searchAll(Contract contract)
            throws Exception {
        if (contract == null) {
            throw new Exception("Exception: contract is null!!");
        }

        try {
            return m_pubTSpace.searchAll(contract);
        } catch (TupleSpaceException e) {
            return null;
        }
    }

    /**
     *  Prints all CyberOrg tuples in this Directory Manager.
     */
    public void printAll() {
        CyberOrgTuple[] cyberOrgTuples = m_pubTSpace.getCyberOrgTuples();

        System.out.println("> CyberOrg Directory Manager: ");
        for (int i = 0; i < cyberOrgTuples.length; i++) {
            System.out.println(i + ":" + cyberOrgTuples[i]);
        }
    }

    //  -----------------
    //   deliver methods 
    //  -----------------
    public boolean deliver(CyberOrgTuple p_ctReceiver, String p_strMethod) {
        return (deliver(p_ctReceiver, p_strMethod, new Object[0]));
    }

    public boolean deliver(CyberOrgTuple p_ctReceiver, String p_strMethod, Serializable p_serArg1) {
        Object[] objaArgs = {p_serArg1};

        return (deliver(p_ctReceiver, p_strMethod, objaArgs));
    }

    public boolean deliver(CyberOrgTuple p_ctReceiver, String p_strMethod, Serializable p_serArg1,
            Serializable p_serArg2) {
        Object[] objaArgs = {p_serArg1, p_serArg2};

        return (deliver(p_ctReceiver, p_strMethod, objaArgs));
    }

    public boolean deliver(CyberOrgTuple p_ctReceiver, String p_strMethod, Serializable p_serArg1,
            Serializable p_serArg2, Serializable p_serArg3) {
        Object[] objaArgs = {p_serArg1, p_serArg2, p_serArg3};

        return (deliver(p_ctReceiver, p_strMethod, objaArgs));
    }

    public boolean deliver(CyberOrgTuple p_ctReceiver, String p_strMethod, Serializable p_serArg1,
            Serializable p_serArg2, Serializable p_serArg3, Serializable p_serArg4) {
        Object[] objaArgs = {p_serArg1, p_serArg2, p_serArg3, p_serArg4};

        return (deliver(p_ctReceiver, p_strMethod, objaArgs));
    }

    public boolean deliver(CyberOrgTuple p_ctReceiver, String p_strMethod, Serializable p_serArg1,
            Serializable p_serArg2, Serializable p_serArg3, Serializable p_serArg4,
            Serializable p_serArg5) {
        Object[] objaArgs = {p_serArg1, p_serArg2, p_serArg3, p_serArg4, p_serArg5};

        return (deliver(p_ctReceiver, p_strMethod, objaArgs));
    }

    public boolean deliver(CyberOrgTuple p_ctReceiver, String p_strMethod, Serializable p_serArg1,
            Serializable p_serArg2, Serializable p_serArg3, Serializable p_serArg4,
            Serializable p_serArg5, Serializable p_serArg6) {
        Object[] objaArgs = {p_serArg1, p_serArg2, p_serArg3, p_serArg4, p_serArg5,
            p_serArg6};

        return (deliver(p_ctReceiver, p_strMethod, objaArgs));
    }

    public boolean deliver(CyberOrgTuple p_ctReceiver, String p_strMethod, Serializable p_serArg1,
            Serializable p_serArg2, Serializable p_serArg3, Serializable p_serArg4,
            Serializable p_serArg5, Serializable p_serArg6, Serializable p_serArg7) {
        Object[] objaArgs = {p_serArg1, p_serArg2, p_serArg3, p_serArg4, p_serArg5,
            p_serArg6, p_serArg7};

        return (deliver(p_ctReceiver, p_strMethod, objaArgs));
    }

    public boolean deliver(CyberOrgTuple p_ctReceiver, String p_strMethod, Serializable p_serArg1,
            Serializable p_serArg2, Serializable p_serArg3, Serializable p_serArg4,
            Serializable p_serArg5, Serializable p_serArg6, Serializable p_serArg7,
            Serializable p_serArg8) {
        Object[] objaArgs = {p_serArg1, p_serArg2, p_serArg3, p_serArg4, p_serArg5,
            p_serArg6, p_serArg7, p_serArg8};

        return (deliver(p_ctReceiver, p_strMethod, objaArgs));
    }

    public boolean deliver(CyberOrgTuple p_ctReceiver, String p_strMethod, Serializable p_serArg1,
            Serializable p_serArg2, Serializable p_serArg3, Serializable p_serArg4,
            Serializable p_serArg5, Serializable p_serArg6, Serializable p_serArg7,
            Serializable p_serArg8, Serializable p_serArg9) {
        Object[] objaArgs = {p_serArg1, p_serArg2, p_serArg3, p_serArg4, p_serArg5,
            p_serArg6, p_serArg7, p_serArg8, p_serArg9};

        return (deliver(p_ctReceiver, p_strMethod, objaArgs));
    }

    public boolean deliver(CyberOrgTuple p_ctReceiver, String p_strMethod, Serializable p_serArg1,
            Serializable p_serArg2, Serializable p_serArg3, Serializable p_serArg4,
            Serializable p_serArg5, Serializable p_serArg6, Serializable p_serArg7,
            Serializable p_serArg8, Serializable p_serArg9, Serializable p_serArg10) {
        Object[] objaArgs = {p_serArg1, p_serArg2, p_serArg3, p_serArg4, p_serArg5,
            p_serArg6, p_serArg7, p_serArg8, p_serArg9, p_serArg10};

        return (deliver(p_ctReceiver, p_strMethod, objaArgs));
    }

    //  --------------------
    //   deliverAll methods
    //  --------------------
    public boolean deliverAll(CyberOrgTuple p_ctReceiver, String p_strMethod) {
        return (deliverAll(p_ctReceiver, p_strMethod, new Object[0]));
    }

    public boolean deliverAll(CyberOrgTuple p_ctReceiver, String p_strMethod, Serializable p_serArg1) {
        Object[] objaArgs = {p_serArg1};

        return (deliverAll(p_ctReceiver, p_strMethod, objaArgs));
    }

    public boolean deliverAll(CyberOrgTuple p_ctReceiver, String p_strMethod, Serializable p_serArg1,
            Serializable p_serArg2) {
        Object[] objaArgs = {p_serArg1, p_serArg2};

        return (deliverAll(p_ctReceiver, p_strMethod, objaArgs));
    }

    public boolean deliverAll(CyberOrgTuple p_ctReceiver, String p_strMethod, Serializable p_serArg1,
            Serializable p_serArg2, Serializable p_serArg3) {
        Object[] objaArgs = {p_serArg1, p_serArg2, p_serArg3};

        return (deliverAll(p_ctReceiver, p_strMethod, objaArgs));
    }

    public boolean deliverAll(CyberOrgTuple p_ctReceiver, String p_strMethod, Serializable p_serArg1,
            Serializable p_serArg2, Serializable p_serArg3, Serializable p_serArg4) {
        Object[] objaArgs = {p_serArg1, p_serArg2, p_serArg3, p_serArg4};

        return (deliverAll(p_ctReceiver, p_strMethod, objaArgs));
    }

    public boolean deliverAll(CyberOrgTuple p_ctReceiver, String p_strMethod, Serializable p_serArg1,
            Serializable p_serArg2, Serializable p_serArg3, Serializable p_serArg4,
            Serializable p_serArg5) {
        Object[] objaArgs = {p_serArg1, p_serArg2, p_serArg3, p_serArg4, p_serArg5};

        return (deliverAll(p_ctReceiver, p_strMethod, objaArgs));
    }

    public boolean deliverAll(CyberOrgTuple p_ctReceiver, String p_strMethod, Serializable p_serArg1,
            Serializable p_serArg2, Serializable p_serArg3, Serializable p_serArg4,
            Serializable p_serArg5, Serializable p_serArg6) {
        Object[] objaArgs = {p_serArg1, p_serArg2, p_serArg3, p_serArg4, p_serArg5,
            p_serArg6};

        return (deliverAll(p_ctReceiver, p_strMethod, objaArgs));
    }

    public boolean deliverAll(CyberOrgTuple p_ctReceiver, String p_strMethod, Serializable p_serArg1,
            Serializable p_serArg2, Serializable p_serArg3, Serializable p_serArg4,
            Serializable p_serArg5, Serializable p_serArg6, Serializable p_serArg7) {
        Object[] objaArgs = {p_serArg1, p_serArg2, p_serArg3, p_serArg4, p_serArg5,
            p_serArg6, p_serArg7};

        return (deliverAll(p_ctReceiver, p_strMethod, objaArgs));
    }

    public boolean deliverAll(CyberOrgTuple p_ctReceiver, String p_strMethod, Serializable p_serArg1,
            Serializable p_serArg2, Serializable p_serArg3, Serializable p_serArg4,
            Serializable p_serArg5, Serializable p_serArg6, Serializable p_serArg7,
            Serializable p_serArg8) {
        Object[] objaArgs = {p_serArg1, p_serArg2, p_serArg3, p_serArg4, p_serArg5,
            p_serArg6, p_serArg7, p_serArg8};

        return (deliverAll(p_ctReceiver, p_strMethod, objaArgs));
    }

    public boolean deliverAll(CyberOrgTuple p_ctReceiver, String p_strMethod, Serializable p_serArg1,
            Serializable p_serArg2, Serializable p_serArg3, Serializable p_serArg4,
            Serializable p_serArg5, Serializable p_serArg6, Serializable p_serArg7,
            Serializable p_serArg8, Serializable p_serArg9) {
        Object[] objaArgs = {p_serArg1, p_serArg2, p_serArg3, p_serArg4, p_serArg5,
            p_serArg6, p_serArg7, p_serArg8, p_serArg9};

        return (deliverAll(p_ctReceiver, p_strMethod, objaArgs));
    }

    public boolean deliverAll(CyberOrgTuple p_ctReceiver, String p_strMethod, Serializable p_serArg1,
            Serializable p_serArg2, Serializable p_serArg3, Serializable p_serArg4,
            Serializable p_serArg5, Serializable p_serArg6, Serializable p_serArg7,
            Serializable p_serArg8, Serializable p_serArg9, Serializable p_serArg10) {
        Object[] objaArgs = {p_serArg1, p_serArg2, p_serArg3, p_serArg4, p_serArg5,
            p_serArg6, p_serArg7, p_serArg8, p_serArg9, p_serArg10};

        return (deliverAll(p_ctReceiver, p_strMethod, objaArgs));
    }
}
